package com.xiaoshuidi.cloud.module.contract.util.bill;


import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.NOT_PAY;

/**
 * 日租金计算
 */
@Slf4j
public class DayRent {

    /**
     * 给定一个时间计算日租金
     *
     * @param startDate   开始时间
     * @param monthAmount 月金额(月租金，月周期性费用)
     */
    public static BigDecimal calculateDailyAmount(LocalDate startDate, BigDecimal monthAmount) {
        assertNotNull(startDate, monthAmount);
        int days = startDate.lengthOfMonth();
        return monthAmount.divide(BigDecimal.valueOf(days), 2, RoundingMode.HALF_UP);
    }


    /**
     *
     * @param remainingAmountList 账单明细
     * @return 返回应退金额
     */
    public static List<RemainingAmount> remainingAmount(List<RemainingAmount> remainingAmountList) {
        for (RemainingAmount item : remainingAmountList) {
            LocalDate refundTime = item.getRefundTime();
            LocalDate startTime = item.getStartTime();
            LocalDate endTime = item.getEndTime();
            if (endTime.isBefore(refundTime) || (!startTime.isAfter(refundTime) && !refundTime.isAfter(endTime))) {
                throw exception(NOT_PAY);
            }
            BigDecimal refundable = remainingAmount(startTime, endTime,
                    refundTime, item.getMonthAmount());
            item.setRemainingAmount(refundable);
        }
        return remainingAmountList;

    }


    /**
     * 账单剩余金额
     * startTime 账单开始时间
     * endTime 账单结束时间
     * refundTime 账单退租时间
     */
    public static BigDecimal remainingAmount(LocalDate startTime, LocalDate endTime,
                                             LocalDate refundTime, BigDecimal monthAmount) {
        assertNotNull(startTime, monthAmount,refundTime,monthAmount);
        List<BillPeriod> billPeriods = BillPeriod.splitByMonth(startTime, endTime, 1);

        BigDecimal refundable=BigDecimal.ZERO;
        for (BillPeriod billPeriod : billPeriods) {
            LocalDate startBillTime = billPeriod.getStartTime();
            LocalDate endBillTime = billPeriod.getEndTime();
            log.info("开始时间：{}，结束时间：{}",startBillTime,endBillTime);
            if (endBillTime.isBefore(refundTime)) {
                continue;
            }
            BigDecimal dayAmount = calculateDailyAmount(startBillTime, monthAmount);
            int rentedDay = BillPeriod.totalDays(startBillTime, refundTime);
            BigDecimal rentedAmount = dayAmount.multiply(BigDecimal.valueOf(rentedDay));
            // 已住天数金额 大于 月费用
            BigDecimal remainingAmount = monthAmount.subtract(rentedAmount);
            if(remainingAmount.compareTo(BigDecimal.ZERO)<0){
                continue;
            }
            if(refundTime.isAfter(startBillTime) &&
                    refundTime.isBefore(endBillTime)){
                refundable=refundable.add(remainingAmount);
            }
            if(startBillTime.isAfter(refundTime)){
                refundable=refundable.add(monthAmount);
            }
        }
        return refundable;
    }

    private static void assertNotNull(LocalDate startTime, BigDecimal endTime) {
        Assert.notNull(startTime, "startTime cannot be null");
        Assert.notNull(endTime, "monthAmount cannot be null");
    }
    private static void assertNotNull(LocalDate startTime, BigDecimal endTime, LocalDate refundTime, BigDecimal monthAmount) {
        Assert.notNull(startTime, "startTime cannot be null");
        Assert.notNull(endTime, "endTime cannot be null");
        Assert.notNull(refundTime, "refundTime cannot be null");
        Assert.notNull(monthAmount, "monthAmount cannot be null");
    }

}
